package com.cpit.platform.service.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.cpit.platform.common.entity.TableDataQueryCondition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cpit.platform.common.constant.SystemConstant;
import com.cpit.platform.common.constant.UserConstant;
import com.cpit.platform.common.entity.TableJsonData;
import com.cpit.platform.common.utils.AuthUtils;
import com.cpit.platform.common.utils.BeanUtil;
import com.cpit.platform.dao.OrganizationRepository;
import com.cpit.platform.dto.Organization;
import com.cpit.platform.dto.OrganizationPair;
import com.cpit.platform.log.LogOperator;
import com.cpit.platform.service.OrganizationService;

@Service
@Transactional
public class OrganizationServiceImpl implements OrganizationService {

    private final String loggerName = this.getClass().getName();

    @Autowired
    private OrganizationRepository rep = null;

    @Override
    public Organization findById(Integer id) {
        return rep.findById(id);
    }

    public List<Organization> findAll() {
        return rep.findAll();
    }

    public void create(Organization data) throws Exception {
        data.setCode(genCode(data.getParentId()));
        checkOrganizationName(data, true);
        rep.save(data);
    }

    public void modify(Organization data) throws Exception {
        checkOrganizationName(data, false);
        rep.save(data);
    }

    public void delete(Organization data) throws Exception {
        List<Organization> plist = rep.findByParentId(data.getId());
        if (plist != null && plist.size() > 0) {
            throw new Exception("存在子机构，禁止删除！");
        }
        rep.delete(data);
    }

    public String findCodeById(int id) {
        if (id == SystemConstant.ORGANIZATION_ID_ROOT) {
            return SystemConstant.ORGANIZATION_CODE_ROOT;
        }
        Organization r = rep.findById(id);
        return r.getCode();
    }

    public List<Organization> findByCondition(int page, int size, String order, String orderBy, String orgName, String orgIdCondition) {
        Direction der = order.equals(SystemConstant.DIRECTION_ASC) ? Direction.ASC : Direction.DESC;
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "id";
        }
        PageRequest request = new PageRequest(page - 1, size, new Sort(der, orderBy));
        OrganizationPair pair;
        try {
            pair = AuthUtils.getCurrentOrganizationCode();
        } catch (Exception e) {
            LogOperator.err(loggerName, "no user login", e);
            return null;
        }
        String curUserOrgCode = pair.organizationCode;
        if (orgIdCondition != null && orgIdCondition.length() > 0) {
            curUserOrgCode = orgIdCondition; // narrown down the range of data
        }
        Page<Organization> pr = null;
        List<Organization> rs = null;
        LogOperator.debug(loggerName, "findByCondition curUserOrgCode: " + curUserOrgCode);
        if (pair.userAuthType.equals(UserConstant.USER_AUTH_TYPE_COMMON)) {
            pr = rep.findByNameContainingAndCode(orgName, curUserOrgCode, request);
        } else if (pair.userAuthType.equals(UserConstant.USER_AUTH_TYPE_AREA_ADMIN)) {
            pr = rep.findByNameContainingAndCodeStartingWith(orgName, curUserOrgCode, request);
        } else {
            pr = rep.findByNameContainingAndCodeStartingWith(orgName, curUserOrgCode, request);
        }
        rs = pr.getContent();
        return rs;
    }

    public List<Organization> findByConditionForTree(int page, int size, String order, String orderBy, String orgName, String orgIdCondition) {
        Direction der = order.equals(SystemConstant.DIRECTION_ASC) ? Direction.ASC : Direction.DESC;
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "id";
        }
        PageRequest request = new PageRequest(page - 1, size, new Sort(der, orderBy));
        OrganizationPair pair;
        try {
            pair = AuthUtils.getCurrentOrganizationCode();
        } catch (Exception e) {
            LogOperator.err(loggerName, "no user login", e);
            return null;
        }
        String curUserOrgCode = pair.organizationCode;
        if (orgIdCondition != null && orgIdCondition.length() > 0) {
            curUserOrgCode = orgIdCondition; // narrown down the range of data
        }
        Page<Organization> pr = null;
        List<Organization> rs = null;
        LogOperator.debug(loggerName, "findByCondition curUserOrgCode: " + curUserOrgCode);
        if (pair.userAuthType.equals(UserConstant.USER_AUTH_TYPE_COMMON)) {
            rs = rep.findByNameAndCodeMatchForTreeCommon(curUserOrgCode);
        } else if (pair.userAuthType.equals(UserConstant.USER_AUTH_TYPE_AREA_ADMIN)) {
            rs = rep.findByNameAndCodeMatchForTree(curUserOrgCode);
        } else {
            pr = rep.findByNameContaining(orgName, request);
            rs = pr.getContent();
        }
        return rs;
    }

    public List<Organization> findByConditionForTreeWithoutSecurity(int page, int size, String order, String orderBy, String orgName, String orgIdCondition) {
        Direction der = order.equals(SystemConstant.DIRECTION_ASC) ? Direction.ASC : Direction.DESC;
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "id";
        }
        PageRequest request = new PageRequest(page - 1, size, new Sort(der, orderBy));

        Page<Organization> pr = null;
        List<Organization> rs = null;

        pr = rep.findByNameContaining(orgName, request);
        rs = pr.getContent();
        return rs;
    }

    @SuppressWarnings("rawtypes")
    public TableJsonData findByConditionJqg(TableDataQueryCondition cond) {
        Direction der = null;
        if (cond.getSord() == null || cond.getSord().length() == 0) {
            der = Direction.ASC;
        } else
            der = cond.getSord().equals(SystemConstant.DIRECTION_ASC) ? Direction.ASC : Direction.DESC;
        if (cond.getSidx() == null || cond.getSidx().length() == 0) {
            cond.setSidx("id");
        }

        PageRequest request = new PageRequest(cond.getPageNumber() - 1, cond.getRowsNumber(),
                new Sort(der, cond.getSidx()));

        OrganizationPair pair;
        try {
            pair = AuthUtils.getCurrentOrganizationCode();
        } catch (Exception e) {
            LogOperator.err(loggerName, "no user login", e);
            return null;
        }
        String curUserOrgCode = pair.organizationCode;
        String orgName = BeanUtil.getStringIdentifyNull(cond.getQueryCond().get("orgName"));
        String orgIdCondition = BeanUtil.getStringIdentifyNull(cond.getQueryCond().get("orgIdCondition"));
        if (orgIdCondition != null && orgIdCondition.length() > 0) {
            curUserOrgCode = orgIdCondition; // narrown down the range of data
        }
        Page<Organization> pr = null;
        LogOperator.debug(loggerName, "findByCondition curUserOrgCode: " + curUserOrgCode);
        if (pair.userAuthType.equals(UserConstant.USER_AUTH_TYPE_COMMON)) {
            pr = rep.findByNameContainingAndCode(orgName, curUserOrgCode, request);
        } else if (pair.userAuthType.equals(UserConstant.USER_AUTH_TYPE_AREA_ADMIN)) {
            pr = rep.findByNameContainingAndCodeStartingWith(orgName, curUserOrgCode, request);
        } else {
            pr = rep.findByNameContainingAndCodeStartingWith(orgName, curUserOrgCode, request);
        }
        return new TableJsonData(cond, pr.getTotalElements(), pr.getContent());
    }

    public String genCode(Integer pid) throws Exception {
        if (pid == null || pid < 0) {
            return "000";
        }
        Organization r = rep.findById(pid);
        String pCode = r.getCode();
        List<Organization> plist = rep.findByParentId(pid);
        // get the min unused code
        if (plist == null || plist.size() == 0) {
            return pCode + "001";
        }
        String code = null;
        List<Integer> allIntLst = new ArrayList<Integer>();
        for (int i = 1; i <= 999; i++) {
            allIntLst.add(i);
        }
        for (Organization org : plist) {
            code = org.getCode();
            String subCode = code.substring(code.length() - 3, code.length());
            int subCodeInt = Integer.parseInt(subCode);
            Iterator<Integer> allIt = allIntLst.iterator();
            while (allIt.hasNext()) {
                int one = allIt.next();
                if (one == subCodeInt) {
                    allIt.remove();
                }
            }
        }
        if (allIntLst.size() <= 0) {
            throw new Exception("organization max number reached");
        }
        int thisCodeInt = allIntLst.get(0);
        if (thisCodeInt < 10) {
            return pCode + "00" + String.valueOf(thisCodeInt);
        } else if (thisCodeInt < 100) {
            return pCode + "0" + String.valueOf(thisCodeInt);
        } else {
            return pCode + String.valueOf(thisCodeInt);
        }
    }

    private void checkOrganizationName(Organization data, boolean isCreate) throws Exception {
        List<Organization> plist = rep.findByParentId(data.getParentId());
        if (plist == null || plist.size() == 0) {
            return;
        } else {
            for (Organization org : plist) {
                if (isCreate == true) {
                    if (data.getName().equals(org.getName())) {
                        throw new Exception("同一父级已有相同的名称，请修改！");
                    }
                } else {
                    if (!data.getId().equals(org.getId()) && data.getName().equals(org.getName())) {
                        throw new Exception("同一父级已有相同的名称，请修改！");
                    }
                }
            }
        }
    }

}
